import 'dart:convert';

import 'package:dartkit/dartkit.dart';
import 'package:shelf/shelf.dart';
import 'package:test/test.dart';

void main() {
  // 颁发token时会用到
  argSecret.value = "test";

  group("错误处理中间件", () {
    test("处理Bug测试", () async {
      // 创建一个永远会返回错误的handler
      final Handler handler =
          Pipeline().addMiddleware(errorHandle).addHandler((_) {
        throw Bug("错误处理测试");
      });
      // 有错误处理中间件，则每次实际上都会返回400的错误
      final request = testRequest();
      final response = await handler(request);
      expect(response.statusCode, 400);
      // 并且解码body后，刚好是这串文字
      final String message = await response.readAsString();
      expect(message, "错误处理测试");
    });

    test("处理其他错误", () async {
      // 创建一个永远会返回错误的handler
      final Handler handler =
          Pipeline().addMiddleware(errorHandle).addHandler((_) {
        throw Exception("其他错误");
      });
      // 有错误处理中间件，则每次实际上都会返回500的错误
      final request = testRequest();
      final response = await handler(request);
      expect(response.statusCode, 500);
      // 并且解码body后，字符串会比较长（因为带上了stack）
      final String message = await response.readAsString();
      expect(message.length > 200, isTrue);
    });
  });

  test("CORS跨域测试", () async {
    // 加上了跨域header的回复
    final Handler handler =
        Pipeline().addMiddleware(cors).addHandler((_) => responseOK());
    // 随便发送一个请求，应该能在回复后收到对应的header
    final response =
        await handler(testRequest(headers: {"Origin": "http://example.com"}));
    final Map<String, String> headers = response.headers;
    expect(headers.containsKey('Access-Control-Allow-Origin'), isTrue);
    expect(headers.containsKey('Access-Control-Allow-Credentials'), isTrue);
    expect(headers.containsKey('Access-Control-Allow-Headers'), isTrue);
    expect(headers.containsKey('Access-Control-Allow-Methods'), isTrue);
  });

  test("登录测试", () async {
    // 分发一个包含某种id的token
    final token = TokenKit.issue(subject: "id");
    // 创建一个登录请求的Handler和一个包含Authorization的请求
    final handler = Pipeline()
        .addMiddleware(redeemToken)
        .addHandler((request) => responseOK(request.subject));
    // 使用不带Authorization的内容请求，或者乱填token，都会收到错误
    final wrong1 = testRequest();
    final response1 = await handler(wrong1);
    expect(response1.statusCode, 401);
    final wrong2 = testRequest(headers: {"Authorization": "acascade"});
    final response2 = await handler(wrong2);
    expect(response2.statusCode, 401);

    // 使用正确的token请求，可以收到200，并能够解码后的主体
    final request3 = testRequest(headers: {"Authorization": token});
    final response3 = await handler(request3);
    final String body = await response3.readAsString();
    expect(body, equals("id"));
  });

  group("管理员检查", () {
    prepareAndCleanPostgres("check_admin_test_db");

    test("常规检查", () async {
      // 创建一个同时包含登录和管理员检查的handler
      final Handler handler = Pipeline()
          .addMiddleware(redeemToken)
          .addMiddleware(checkAdmin)
          .addHandler((_) => responseOK());
      // 创建一个用户，并获取它的id，分发一个token
      final User user = await userTable.findOrCreate("12345678901");
      final String token = TokenKit.issue(subject: user.id.toString());
      // 在请求中加入token
      final request = testRequest(headers: {"Authorization": token});

      // 此时发送请求，由于用户并不是管理员，会收到403错误
      final response1 = await handler(request);
      expect(response1.statusCode, 403);

      // 将用户的管理员权限修改后，再次发送同样的请求，此时会收到200错误
      user.isAdmin = true;
      await userTable.update(user);
      final response2 = await handler(request);
      expect(response2.statusCode, 200);
    });
  });

  group("获取json格式的body", () {
    // 创建一个必定成功的handler（共用），并且将传入的body原封不动返回
    // 因此如果body获取的过程出错的话，肯定会以Bug的形式暴露出来
    // 但是实际上真正使用时是安全的
    final Handler readBodyHandler =
        Pipeline().addMiddleware(getBody).addHandler((_) {
      final body = _.body;
      return response(200, body);
    });

    test("没有body内容", () async {
      // 创建一个空的request，读取时会出错
      final Request request = testRequest();
      expect(() async => await readBodyHandler(request), isBug);
    });

    test("json格式错误", () async {
      // 创建一个错误格式的request，读取时会出错
      final Request request = testRequest(body: "not json");
      expect(() async => await readBodyHandler(request), isBug);
    });

    test("不要List格式的json", () async {
      // 创建一个List作为数据，发送，收获400
      final Request request = testRequest(body: ["not json"]);
      expect(() async => await readBodyHandler(request), isBug);
    });

    test("正常返回", () async {
      // 创建正确格式的json，能够收到response，并且数据是相同的
      final Request request = testRequest(body: {"a": "b"});
      final response = await readBodyHandler(request);
      expect(response.statusCode, 200);
      // 解析response的body，可以得到我传入的结果
      final String bodyStr = await response.readAsString();
      final Json body = jsonDecode(bodyStr);
      expect(body, hasLength(1));
      expect(body["a"], equals("b"));
    });
  });
}
